﻿using System;
using System.Collections.Generic;
using Blackbird.Common.Exceptions;

namespace Blackbird.Common.Logging
{
    /// <summary>
    /// Provides a convienient singleton for routing logging calls to a display or other output method.
    /// </summary>
    public static class LogManager
    {
        private static readonly List<ILogEntryReceiver> Receivers = new List<ILogEntryReceiver>();

        /// <summary>
        /// Binds a the static LogManager object to an instance of an object supporting the ILogEntryReceiver interface.
        /// </summary>
        /// <param name="logReceiver">A non-null object that implements the ILogEntryReceiver interface.</param>
        public static void BindReceiver(ILogEntryReceiver logReceiver)
        {
            Receivers.Add(logReceiver);
        }

        /// <summary>
        /// Unbinds the LogManager from all of the currently bound receivers.
        /// </summary>
        public static void ClearBindings()
        {
            Receivers.Clear();
        }

        /// <summary>
        /// Unbinds the LogManager from a specific receiver.
        /// </summary>
        /// <param name="name">The name of the receiver to unbind.</param>
        public static void ClearBinding(string name)
        {
            Receivers.Remove(Receivers.Find(r => r.Name == name));
        }

        /// <summary>
        /// Adds a log entry.
        /// </summary>
        /// <param name="logEntry">An instance of the log entry to add to the log.</param>
        public static void LogMessage(LogEntry logEntry)
        {
            Validate();
            foreach (ILogEntryReceiver receiver in Receivers)
            {
                if ((int) logEntry.LogEntryType >= (int) receiver.Level)
                    receiver.LogMessage(logEntry);
            }
        }

        /// <summary>
        /// Adds a log entry.
        /// </summary>
        /// <param name="type">The type of log message to add to the log.</param>
        /// <param name="message">The message text to add to the log.</param>
        public static void LogMessage(LogEntryType type, string message)
        {
            Validate();
            LogMessage(new LogEntry(type, message));
        }

        /// <summary>
        /// Adds a log entry.
        /// </summary>
        /// <param name="type">The type of message to add to the log.</param>
        /// <param name="format">The string format to add to the log via string.Format(format, args).</param>
        /// <param name="args">The string format arguments to add to the log via string.Format(format, args).</param>
        public static void LogMessage(LogEntryType type, string format, params object[] args)
        {
            if (args == null) throw new ArgumentNullException("args");
            Validate();
            LogMessage(new LogEntry(type, format, args));
        }

        /// <summary>
        /// Clears the log.
        /// </summary>
        public static void Clear()
        {
            Validate();
            Receivers.ForEach(receiver => receiver.Clear());
        }

        /// <summary>
        /// Refreshes the view of the log, causing it to be redrawn.
        /// </summary>
        public static void Refresh()
        {
            Validate();
            Receivers.ForEach(receiver => receiver.Refresh());
        }

        /// <summary>
        /// Checks to see that the ILogEntryReceiver list has been properly bound to a non-null ILogEntryReceiver object.
        /// </summary>
        private static void Validate()
        {
            if (Receivers.Count == 0)
                throw new LogNotBoundException();
        }
    }
}